<html>
<head>
<title>CpcPaChi - Version 0.09</title>
<style type="text/css">
span {
  font-family: 'Courier New';
  font-size: 10pt;
  color: #000000;
}
.sc0 {
  color: #808080;
}
.sc3 {
  color: #008080;
}
.sc4 {
  color: #FF8000;
}
.sc5 {
  font-weight: bold;
  color: #0000FF;
}
.sc7 {
  color: #808080;
}
.sc9 {
  color: #804000;
}
.sc10 {
  font-weight: bold;
  color: #000080;
}
.sc11 {
}
</style>
</head>
<body>
<h2>Un compilador sencillo paso a paso (9 - Acercamiento a las variables)</h2>

<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>

<p>Ya hab&iacute;amos preparado una primera tabla de s&iacute;mbolos, que nos permit&iacute;a  utilizar constantes en los programas. Ahora vamos a ampliar ligeramente la estructura para permitir el manejo b&aacute;sico de variables.</p>

<p>De cada s&iacute;mbolo est&aacute;bamos guardando el nombre, el tipo (por ahora s&oacute;lo byte) y el valor. En un principio, nos podr&iacute;a bastar para un manejo b&aacute;sico de variables a nuesto nivel. Aun as&iacute;, hay otra diferencia entre el manejo de constantes y variables: una constante se declara a la vez que se le da un valor, pero una variable no: primero se declara y luego se le da un valor. Esto puede provocar que intentemos usar una variable que se ha declarado pero que todav&iacute;a no tiene un valor. Hay tres formas de atacar este problema: </p>
<ul>
  <li>Ignorarlo, con lo cual se podr&aacute; acceder al valor de una variable a la que realmente no se ha dado valor, y que contendr&aacute; basura. Es lo que se suele hacer e los compiladores de C. </li>
<li>Dar un valor a las variables cuando se declaren. Por ejemplo, se podr&iacute;a dar por sentado que una variable num&eacute;rica tendr&aacute; un valor inicial de cero. Es lo que se suele hacer en muchas versiones de Basic. </li>
<li>Anotar si se ha dado un valor a la variable o no, y mostrar un mensaje de error si se intenta usar una variable que no tiene valor. En el momento de compilar se puede hacer una primera estimaci&oacute;n, y avisar de los posibles errores, como se hace en Java, pero la mayor&iacute;a de comprobaciones &quot;reales&quot; habr&iacute;a que hacerlas en tiempo de ejecuci&oacute;n.</li>
</ul>
<p>Yo seguir&eacute; la primera aproximaci&oacute;n: reservar&eacute; un espacio para cada variable, no le dar&eacute; un valor incial, y no comprobar&eacute; si la variable ten&iacute;a valor cuando se acceda a ella.</p>
<p>Habr&aacute; que modificar la tabla de s&iacute;mbolos ligeramente, porque de las variables no guardaremos su valor actual, sino la direcci&oacute;n de memoria en que se encuentran.</p>
<p>Tambi&eacute;n habr&aacute; que ampliar ligeramente el analizador l&eacute;xico: ahora, adem&aacute;s del bloque CONST, podr&aacute; haber un bloque VAR, y ambos ser&aacute;n opcionales, por lo que esa parte del an&aacute;lisis sint&aacute;ctico podr&iacute;a ser:</p>

<pre><code>
do {
  orden = miLexer.ObtenerIdentificador().ToUpper();

  if ( orden == "CONST" )
    analizarCONST();
  else if ( orden == "VAR" )
    analizarVAR();
  else if ( orden != "BEGIN" )
  {
    Console.WriteLine("No se ha encontrado BEGIN");
    Environment.Exit(1);
  }
}
while ( orden != "BEGIN" );
</code></pre>

<p>El an&aacute;lisis sint&aacute;ctico de la orden VAR ser&iacute;a muy parecido al de CONST:</p>

<pre><code>
void analizarVAR()
{
  string identificador = miLexer.ObtenerIdentificador();
  miLexer.LeerSimbolo(':');
  string tipoVariable = miLexer.ObtenerIdentificador();
  if ( tipoVariable != &quot;BYTE&quot; )
    miLexer.ErrorFatal(&quot;Tipo de datos incorrecto&quot;);
  miTablaSimb.Insertar(identificador, tipoId.VAR,
    tamDato.BYTE, 0 );
  char terminador = miLexer.LeerCualquierSimbolo();
  if ( (terminador != ';') &amp;&amp; (terminador != ',') )
    miLexer.ErrorFatal(&quot;Terminador incorrecto: {0}&quot; + terminador);

  if (terminador == ',')
    analizarVAR();
}
</code></pre>



<p>Como se puede ver, ah&iacute; aparece una orden &quot;errorFatal&quot; que no exist&iacute;a antes. Es una peque&ntilde;a mejora al an&aacute;lisis l&eacute;xico: llevar cuenta de la l&iacute;nea y la columna en que estamos, para poder dar mensajes de error un poco m&aacute;s detallados. Reemplazar&aacute; a los WriteLine con mensajes de error seguidos de Exit que est&aacute;bamos usando hasta ahora :</p>

<pre><code>
public void ErrorFatal(string mensaje)
{
  Console.Write("Linea: {0}, Pos: {1}. ",
      numeroLineaActual, posicionLineaActual+1);
  Console.WriteLine(mensaje);
  Environment.Exit(1);
}
</code></pre>


<p>De paso, podemos preparar el reconocimiento de las &oacute;rdenes de asignaci&oacute;n de valor a una variable, como &quot;numero := 5;&quot;, aunque todav&iacute;a no generaremos el c&oacute;digo m&aacute;quina correspondiente a ellas.</p>

<pre><code>
void analizarASIGN( string identif )
{
  //   ## Provisional: no deberia permitir espacio entre : y =
  miLexer.LeerSimbolo(':');
  miLexer.LeerSimbolo('=');
  int valor = miLexer.ObtenerEntero();
  miLexer.LeerSimbolo(';');
  //miGenerador.genASIGN(identif,valor);
}
</code></pre>


<p>La parte complicada del manejo de variables no es &eacute;sta, sino la que est&aacute; por llegar. Tras dar valores a variables, habr&aacute; que hacer que se guarden en la posici&oacute;n de memoria que le hayamos reservado. Se deber&aacute; poder leer el valor de una variable. Se deber&aacute; poder hacer operaciones simples, como el incremento (INC) y el decremento (DEC). Eso lo haremos en el pr&oacute;ximo acercamiento. Otras operaciones m&aacute;s complejas, como las aritm&eacute;ticas y las comparaciones tardar&aacute;n un poco m&aacute;s en llegar...</p>
<p><br>
  Como siempre, para m&aacute;s detalles, todo el c&oacute;digo est&aacute; en la p&aacute;gina del proyecto en Google Code:<br />
  <br />
  <a href="http://code.google.com/p/cpcpachi/">http://code.google.com/p/cpcpachi/</a></p>
<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>
</body>
</html>
